﻿using System;
using Hive.Core.Common.Shell;

namespace Hive.Core.Model.Commands
{
    internal class PackageBranchUtils
    {
        public static void PreOrderTraversal(IPackageBranch packageBranch, RecursionMode recursionMode, Action<IPackageBranch> action)
        {
            if (recursionMode != RecursionMode.Dependencies)
            {
                action(packageBranch);
            }

            if (recursionMode != RecursionMode.Self)
            {
                foreach (IPackageBranch dependency in packageBranch.GetDependencies())
                {
                    PreOrderTraversal(dependency, RecursionMode.All, action);
                }
            }
        }

        public static void PostOrderTraversal(IPackageBranch packageBranch, RecursionMode recursionMode, Action<IPackageBranch> action)
        {
            if (recursionMode != RecursionMode.Self)
            {
                foreach (IPackageBranch dependency in packageBranch.GetDependencies())
                {
                    PostOrderTraversal(dependency, RecursionMode.All, action);
                }
            }

            if (recursionMode != RecursionMode.Dependencies)
            {
                action(packageBranch);
            }
        }

        public static void GetMissingPackageBranchRecursively(IPackageBranch packageBranch, RecursionMode recursionMode, IShell shell)
        {
            PreOrderTraversal(packageBranch, recursionMode, dependency =>
            {
                if (!dependency.IsPresent())
                    GetMissingPackageBranch(dependency, shell);
            });
        }

        public static void GetMissingPackageBranch(IPackageBranch packageBranch, IShell shell)
        {
            for (;;)
            {
                string answer = shell.Prompt(
                        string.Format("Missing required branch '{0}' of package '{1}'.\nWould you like to get its source, get its binary or ignore it?  (S/B/I)",
                        packageBranch.Package.Name, packageBranch.Name));
                answer = answer.ToLowerInvariant();
                
                switch (answer)
                {
                    case "s":
                    case "source":
                        packageBranch.GetSource(shell);
                        return;

                    case "b":
                    case "binary":
                        packageBranch.GetBinary(null, shell);
                        return;

                    case "i":
                    case "ignore":
                        return;
                }
            }
        }
    }
}
